package cn.sdormitory.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONObject;
import cn.sdormitory.basedata.dao.BClassDao;
import cn.sdormitory.basedata.dao.BDormitoryDao;
import cn.sdormitory.basedata.dao.BStudentDao;
import cn.sdormitory.basedata.entity.BClass;
import cn.sdormitory.basedata.entity.BDormitory;
import cn.sdormitory.basedata.entity.BStudent;
import cn.sdormitory.basedata.vo.BClassVo;
import cn.sdormitory.common.utils.DateTimeUtils;
import cn.sdormitory.dormitoryHygiene.dao.*;
import cn.sdormitory.dormitoryHygiene.entity.DormitoryHygiene;
import cn.sdormitory.dormitoryHygiene.entity.DormitoryHygieneItem;
import cn.sdormitory.dormitoryHygiene.entity.DormitoryHygienePhoto;
import cn.sdormitory.dormitoryHygiene.entity.DormitoryHygieneStudent;
import cn.sdormitory.dormitoryHygiene.req.SubmitHygieneInfoReq;
import cn.sdormitory.dormitoryHygiene.vo.AppDorHygieneCountVO;
import cn.sdormitory.dormitoryHygiene.vo.AppDormitoryHygieneVO;
import cn.sdormitory.dormitoryHygiene.vo.DormitoryHygieneListVO;
import cn.sdormitory.leavingSchool.dao.LeavingSchoolCertificateDao;
import cn.sdormitory.leavingSchool.entity.LeavingSchoolCertificate;
import cn.sdormitory.service.AppClassService;
import cn.sdormitory.service.AppDormitoryHygieneService;
import cn.sdormitory.sys.dao.SysDeptDao;
import cn.sdormitory.sys.dao.SysDictDetailDao;
import cn.sdormitory.sys.dao.SysUserDao;
import cn.sdormitory.sys.entity.SysDictDetail;
import cn.sdormitory.sys.entity.SysUser;
import cn.sdormitory.sys.service.SysUserRoleService;
import cn.sdormitory.wx.entity.WechatPushMessage;
import cn.sdormitory.wx.mapper.WechatPushMessageMapper;
import cn.sdormitory.wx.utils.WXUtil;
import cn.sdormitory.wx.utils.WeatherDataCreator;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author : yy
 * @date: 2024/9/14 10:50
 * @description:
 */
@Service
public class AppDormitoryHygieneServiceImpl implements AppDormitoryHygieneService {
    @Resource
    private AppDormitoryHygieneDao appDormitoryHygieneDao;
    @Resource
    private DormitoryHygieneDao dormitoryHygieneDao;
    @Resource
    private DormitoryHygieneItemDao dormitoryHygieneItemDao;
    @Resource
    private DormitoryHygieneStudentDao dormitoryHygieneStudentDao;
    @Resource
    private DormitoryHygienePhotoDao dormitoryHygienePhotoDao;
    @Resource
    private BStudentDao bStudentDao;

    @Resource
    private BClassDao classDao;
    @Resource
    private SysUserDao sysUserDao;
    @Resource
    private WeatherDataCreator weatherDataCreator;

    @Resource
    private SysDictDetailDao sysDictDetailDao;

    @Resource
    private BDormitoryDao bDormitoryDao;

    @Resource
    private WXUtil wxUtil;

    @Value("${wxsmall.dorHygiene_temp_id}")
    private String dorHygiene_temp_id;

    @Resource
    private LeavingSchoolCertificateDao schoolCertificateDao;

    @Resource
    private WechatPushMessageMapper wechatPushMessageMapper;

    @Resource
    private SysUserRoleService sysUserRoleService;

    @Resource
    private SysDeptDao sysDeptDao;

    @Override
    public List<AppDormitoryHygieneVO> getEachLayerDormitoryHygiene(String buildNo, String floorNo, Integer checkItemSpan) {
        return appDormitoryHygieneDao.getEachLayerDormitoryHygiene(buildNo,floorNo,checkItemSpan);
    }

    @Override
    public AppDormitoryHygieneVO getDormitoryHygieneDetails(Long dormitoryId, Integer checkItemSpan,String rq) {
        AppDormitoryHygieneVO appDormitoryHygieneVO = new AppDormitoryHygieneVO();

        LambdaQueryWrapper<DormitoryHygiene> dormitoryHygieneWrapper = new LambdaQueryWrapper<>();
        dormitoryHygieneWrapper.eq(DormitoryHygiene::getDormitoryId,dormitoryId);
        dormitoryHygieneWrapper.eq(DormitoryHygiene::getCheckTimeSpan,checkItemSpan);
        dormitoryHygieneWrapper.eq(DormitoryHygiene::getCheckDate, DateTimeUtils.strToDate(rq));
        DormitoryHygiene dormitoryHygiene = dormitoryHygieneDao.selectOne(dormitoryHygieneWrapper);

        if (!Optional.ofNullable(dormitoryHygiene).isPresent()) {
            return null;
        }

        appDormitoryHygieneVO.setDormitoryHygieneId(dormitoryHygiene.getId());
        appDormitoryHygieneVO.setDormitoryId(dormitoryId);
        appDormitoryHygieneVO.setGrade(dormitoryHygiene.getGrade());

        LambdaQueryWrapper<DormitoryHygieneItem> itemWrapper = new LambdaQueryWrapper<>();
        itemWrapper.eq(DormitoryHygieneItem::getDormitoryHygieneId,dormitoryHygiene.getId());
        List<DormitoryHygieneItem> dormitoryHygieneItems = dormitoryHygieneItemDao.selectList(itemWrapper);
        if(!dormitoryHygieneItems.isEmpty()) {
            appDormitoryHygieneVO.setDormitoryHygieneItemList(dormitoryHygieneItems);
        }
        LambdaQueryWrapper<DormitoryHygieneStudent> studentWrapper = new LambdaQueryWrapper<>();
        studentWrapper.eq(DormitoryHygieneStudent::getDormitoryHygieneId,dormitoryHygiene.getId());
        List<DormitoryHygieneStudent> dormitoryHygieneStudents = dormitoryHygieneStudentDao.selectList(studentWrapper);
        if(!dormitoryHygieneStudents.isEmpty()) {
            appDormitoryHygieneVO.setDormitoryHygieneStudentList(dormitoryHygieneStudents);
        }
        LambdaQueryWrapper<DormitoryHygienePhoto> photoWrapper = new LambdaQueryWrapper<>();
        photoWrapper.eq(DormitoryHygienePhoto::getDormitoryHygieneId,dormitoryHygiene.getId());
        List<DormitoryHygienePhoto> hygienePhotoList = dormitoryHygienePhotoDao.selectList(photoWrapper);
        appDormitoryHygieneVO.setPhotos(hygienePhotoList);
        return appDormitoryHygieneVO;
    }

    @Override
    @Transactional
    public void submitHygiene(SubmitHygieneInfoReq hygieneInfoReq) {
        LambdaQueryWrapper<DormitoryHygiene> hygieneWrapper = new LambdaQueryWrapper<>();
        hygieneWrapper.eq(DormitoryHygiene::getCheckTimeSpan,hygieneInfoReq.getCheckTimeSpan());
        hygieneWrapper.eq(DormitoryHygiene::getDormitoryId,hygieneInfoReq.getDormitoryId());
        hygieneWrapper.apply("DATE(check_date) = CURDATE()");
        DormitoryHygiene dormitoryHygiene = dormitoryHygieneDao.selectOne(hygieneWrapper);

        //新增修改宿舍卫生信息
        DormitoryHygiene hygiene = new DormitoryHygiene();
        hygiene.setGrade(hygieneInfoReq.getGrade());
        hygiene.setCheckUser(hygieneInfoReq.getCheckUser());
        if(Optional.ofNullable(dormitoryHygiene).isPresent()) {
            hygiene.setId(dormitoryHygiene.getId());
            dormitoryHygieneDao.updateById(hygiene);

            LambdaQueryWrapper<DormitoryHygieneItem> itemWrapper = new LambdaQueryWrapper<>();
            itemWrapper.eq(DormitoryHygieneItem::getDormitoryHygieneId,hygiene.getId());
            dormitoryHygieneItemDao.delete(itemWrapper);

            LambdaQueryWrapper<DormitoryHygieneStudent> studentWrapper = new LambdaQueryWrapper<>();
            studentWrapper.eq(DormitoryHygieneStudent::getDormitoryHygieneId,hygiene.getId());
            dormitoryHygieneStudentDao.delete(studentWrapper);
        }else {
            hygiene.setDormitoryId(hygieneInfoReq.getDormitoryId());
            hygiene.setCheckDate(new Date());
            hygiene.setCheckTimeSpan(hygieneInfoReq.getCheckTimeSpan());
            dormitoryHygieneDao.insert(hygiene);
        }

        List<DormitoryHygieneItem> hygieneItemList = hygieneInfoReq.getDormitoryHygieneItemList();
        for ( DormitoryHygieneItem item : hygieneItemList) {
            if (Objects.isNull(item.getGrade())) {
                continue;
            }
            item.setDormitoryHygieneId(hygiene.getId());
            dormitoryHygieneItemDao.insert(item);
        }

        List<DormitoryHygieneStudent> studentList = hygieneInfoReq.getDormitoryHygieneStudentList();
        for ( DormitoryHygieneStudent item : studentList) {
            item.setDormitoryHygieneId(hygiene.getId());
            dormitoryHygieneStudentDao.insert(item);
        }

        List<Long> delPhotoIds = hygieneInfoReq.getDelPhotoIds();
        if(!delPhotoIds.isEmpty()) {
            dormitoryHygienePhotoDao.deleteBatchIds(delPhotoIds);
        }

        List<String> photos = hygieneInfoReq.getPhotos();
        for(String photo : photos) {
            DormitoryHygienePhoto hygienePhoto = new DormitoryHygienePhoto();
            hygienePhoto.setDormitoryHygieneId(hygiene.getId());
            hygienePhoto.setPhoto(photo);
            dormitoryHygienePhotoDao.insert(hygienePhoto);
        }




        //月假卫生检查
        if ( hygieneInfoReq.getCheckTimeSpan() == 0 ) {
            //查询该宿舍下的学生
            List<BStudent> students = bStudentDao.getStudentByDormitoryId(hygieneInfoReq.getDormitoryId());
            List<Long> stuIds = students.stream()
                    .map(BStudent::getId)
                    .collect(Collectors.toList());

            LambdaQueryWrapper<LeavingSchoolCertificate> certificateWrapper = new LambdaQueryWrapper<>();
            certificateWrapper.in(LeavingSchoolCertificate::getStudentId,stuIds);
            certificateWrapper.apply("DATE(leave_date) = CURDATE()");
            schoolCertificateDao.delete(certificateWrapper);

            if(hygieneInfoReq.getGrade() != 3) { //生成离校凭证
                for(BStudent bStudent : students) {
                    LeavingSchoolCertificate certificate = new LeavingSchoolCertificate();
                    certificate.setStudentId(bStudent.getId());
                    certificate.setLeaveDate(new Date());
                    schoolCertificateDao.insert(certificate);
                }
            }
        }
    }


    @Override
    public void pushDorHygieneInfo(Long dormitoryId, Integer grade,Integer checkTimeSpan,String rq) {
        //检查结果
        String hygieneResult="优秀";
        if (grade == 2) {
            hygieneResult = "良";
        } else if (grade == 3){
            hygieneResult = "差";
        }

        //查询宿舍楼栋
        BDormitory bDormitory = bDormitoryDao.selectById(dormitoryId);
        LambdaQueryWrapper<SysDictDetail> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysDictDetail::getDictType,"sys_building")
                .eq(SysDictDetail::getDictValue,bDormitory.getBuildingNo());
        SysDictDetail dict = sysDictDetailDao.selectOne(wrapper);
        String buildName = dict.getDictLabel();

        //查询该宿舍下的学生对应的班主任
        List<BStudent> students = bStudentDao.getStudentByDormitoryId(dormitoryId);
        Set<Long> classIds = new HashSet<>();
        for (BStudent student : students) {
            classIds.add(student.getClassId());
        }
        List<BClass> bClasses = classDao.selectBatchIds(classIds);
        Set<Long> teacherIds = new HashSet<>();
        for (BClass bClass : bClasses) {
            teacherIds.add(bClass.getClassTeacherId());
        }
        //班主任信息集合
        List<SysUser> teachers = sysUserDao.selectBatchIds(teacherIds);

        //消息推送
        for (SysUser sysUser : teachers) {
            //判断班主任openid是否为空，不为空则根据openid推送模板信息
            if(!StringUtils.isEmpty(sysUser.getWxOpenId())) {
                //消息封装
                Map<String, Object> weatherDataMap = weatherDataCreator.createDorHygieneWeatherDataMap(buildName,bDormitory.getDormitoryNo(),hygieneResult, DateUtil.formatDateTime(new Date()));

                WechatPushMessage wechatPushMessage = new WechatPushMessage();
                wechatPushMessage.setTemplateId(dorHygiene_temp_id);
                wechatPushMessage.setContent(weatherDataMap.toString());
                wechatPushMessage.setReceiverOpenId(sysUser.getWxOpenId());
                try {
                    String url = "pages_duty/classTeacher/dormitoryHygiene/HygieneDetails?dormitoryId="+dormitoryId+
                            "&dormitoryNo="+bDormitory.getDormitoryNo()+"&checkTimeSpan="+checkTimeSpan+"&rq="+rq;
                    JSONObject jsonObject = wxUtil.sendInfo(sysUser.getWxOpenId(), dorHygiene_temp_id
                            , weatherDataMap,url);
                    wechatPushMessage.setStatus(true);
                    wechatPushMessage.setBackInfo(jsonObject.get("errmsg").toString());
                }catch (Exception e) {
                    System.out.println(e.getMessage());
                    wechatPushMessage.setStatus(false);
                    wechatPushMessage.setBackInfo(e.getMessage());
                }
                wechatPushMessageMapper.insert(wechatPushMessage);
            }
        }
    }



    @Override
    public List<AppDorHygieneCountVO> getAppDorHygieneCount(Long userId,String rq) {
        boolean isDeptManager = false ; //是否部门经理
        List<Long> roleIdList = sysUserRoleService.listRoleIdByUserId(userId);
        for (Long roleId : roleIdList) {
            if(roleId == 2) {
                isDeptManager = true ;
                break;
            }
        }
        List<BClassVo> classList = new ArrayList<>();
        if(isDeptManager) {
            SysUser user = sysUserDao.selectById(userId);
            List<Long> deptIds = sysDeptDao.getAllChildByParent(user.getDeptId());
            //classList = classDao.getAppClassDeptByClaId(user.getDeptId());
            classList = classDao.getAppClassByDeptIds(deptIds);
        }else {
            List<BClassVo> cList = classDao.getAppClassListByTeaId(userId);
            for (BClassVo bClassVo : cList) {
                LambdaQueryWrapper<BStudent> wrapper = new LambdaQueryWrapper<>();
                wrapper.eq(BStudent::getClassId, bClassVo.getClassId())
                        .eq(BStudent::getIsGraduated, "0");
                List<BStudent> studentList = bStudentDao.selectList(wrapper);
                if (!studentList.isEmpty()) {
                    classList.add(bClassVo);
                }
            }
        }

        return classList.parallelStream()
                .map(classVo -> {
                    Long classId = classVo.getClassId();
                    AppDorHygieneCountVO countVO = new AppDorHygieneCountVO();
                    countVO.setClassName(classVo.getClassName());
                    countVO.setClassId(classId);

                    Long classNum = classDao.getStuCountByClaId(classId);
                    countVO.setClassNum(classNum);

                    Integer liveNum = classDao.getBoardingStuCountByClassId(classId.toString());
                    countVO.setLiveNum(liveNum);

                    List<Long> dorIds = classDao.getDorIdsByClassId(classId);

                    if (!dorIds.isEmpty()) {

                        countVO.setDorNum(dorIds.size()); //宿舍个数

                        //查询宿舍卫生检查结果
                        LambdaQueryWrapper<DormitoryHygiene> wrapper = new LambdaQueryWrapper<>();
                        wrapper.in(DormitoryHygiene::getDormitoryId,dorIds);
                        wrapper.eq(DormitoryHygiene::getCheckDate,DateTimeUtils.strToDate(rq));
                        List<DormitoryHygiene> dorHygieneCheck = dormitoryHygieneDao.selectList(wrapper);

                        //已检查个数
                        long checkNum = dorHygieneCheck.stream()
                            .map(DormitoryHygiene::getDormitoryId)
                            .collect(Collectors.toSet())
                            .size();
                        //未检查数
                        long noCheckNum = dorIds.size() - checkNum;
                        countVO.setNoCheckNum(noCheckNum);

                        //不合格数
                        Set<Long> dormitoryIdsWithPoorGrade = dorHygieneCheck.stream()
                                .filter(vo -> vo.getGrade() == 3)
                                .map(DormitoryHygiene::getDormitoryId)
                                .collect(Collectors.toSet());
                        long badDorNum = dormitoryIdsWithPoorGrade.size();
                        countVO.setBadDorNum(badDorNum);

                        //合格数
                        long goodCheckNum = checkNum - badDorNum;
                        countVO.setGoodDorNum(goodCheckNum);
                    }else {
                        countVO.setDorNum(0);
                        countVO.setBadDorNum(0L);
                        countVO.setNoCheckNum(0L);
                        countVO.setGoodDorNum(0L);
                    }

                    return countVO;
                })
                .collect(Collectors.toList());
    }

    @Override
    public List<DormitoryHygieneListVO> getBadDorHygieneByClassId(Long classId,String rq) {
        List<Long> dorIds = classDao.getDorIdsByClassId(classId);
        if(dorIds.isEmpty()) {
            return null;
        }

        return appDormitoryHygieneDao.getDorHygieneByClassId(dorIds,rq);

    }
}
